package cn.edu.nju.ws.sview.wyge.relations.adataset.relations.qxliu.relation;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;

import com.hp.hpl.jena.sparql.function.library.e;
import com.hp.hpl.jena.vocabulary.RDF;

import cn.edu.nju.ws.sview.database.DBConnectionFactory;

public class Expand {
	ArrayList<String[]> patterns = null;
	ArrayList<ArrayList<String>> results = null;
	ArrayList<ArrayList<String>> triples = null;//triples from falcons
	ArrayList<String> tripleRows = null;
	String vi = null;
	String nvname = null;
	public static void main(String[] args){
		ArrayList<String[]> patterns = new ArrayList<String[]>();
		patterns.add(new String[]{"v1","uhttp://www.w3.org/2000/01/rdf-schema#domain","v2"});//(new String[]{"v1","uhttp://purl.org/dc/elements/1.1/creator","v2"});//(new String[]{"v1","uhttp://www.w3.org/2000/01/rdf-schema#label","v2"});//(new String[]{"v1","uhttp://xmlns.com/foaf/0.1/knows","v2"});//
		//patterns.add(new String[]{"v1","uhttp://www.w3.org/2000/01/rdf-schema#comment","v3"});
		patterns.add(new String[]{"v1","uhttp://www.w3.org/2000/01/rdf-schema#range","uhttp://www.w3.org/2002/07/owl#Thing"});
		ArrayList<Integer> d = new ArrayList<Integer>();
		d.add(477821);//(10849124);//(10849110);//(181903600);//(30900);//(4860);//(322960);//(38470);//
		String vi="v1";
		System.out.println("expand:\n"+new Expand().expand(patterns, d, vi));
	}
	
	public ArrayList<ArrayList<String>> expand(ArrayList<String []> patterns, ArrayList<Integer> doc_id, String vi){
		ArrayList<ArrayList<String>> expandPatterns = new ArrayList<ArrayList<String>>();
		ArrayList<String> stringPatterns = new ArrayList<String>();//stringPatterns.get(i) = expandPatterns.get(i).toString()
		
		this.patterns = (ArrayList<String[]>) patterns.clone();
		
		RelationEvaluation re = new RelationEvaluation();
		this.results = re.getValuesFromPatterns(patterns, doc_id);
//		System.out.println("resluts:\n"+results.toString());
		
		//name variables
		int count = -1;
		for(String variable : this.results.get(0)){
			int i = Integer.valueOf(variable.substring(1));//remove "v"
			if(i>count){
				count = i;
			}
		}
		nvname="v"+(count+1);		
		
		if(this.triples == null){
			this.getTriples(doc_id);
			this.tripleRows = new ArrayList<String>();
			for(ArrayList<String> row :this.triples){
				tripleRows.add(row.toString());
			}
		}
//		System.out.println("triples:\n"+this.triples.toString());
		this.vi = vi;
		int idx_vi = results.get(0).indexOf(vi);
		ArrayList<String> constants_vi = new ArrayList<String>();
		String cvi = null;
		for(ArrayList<String> row : results){
			cvi = row.get(idx_vi);
			if(constants_vi.contains(cvi)){
				continue;
			}else{
//				System.out.println("result row:"+row.toString());
				ArrayList<ArrayList<String>> relatedTriples = this.getRelatedTriples(cvi);
				if(this.removeTriples(row,relatedTriples)){
					constants_vi.add(cvi);
					this.conclude(relatedTriples, cvi, expandPatterns, stringPatterns);
				}
			}
		}//end of for
		
		/*//name variables
		int count = -1;
		for(String variable : this.results.get(0)){
			int i = Integer.valueOf(variable.substring(1));//remove "v"
			if(i>count){
				count = i;
			}
		}
		count++;
		for(int i=0; i<expandPatterns.size(); i++){
			ArrayList<String> p = expandPatterns.get(i);
			for(int j=0; j<p.size(); j++){
				if(p.get(j).contentEquals("v")){
					p.set(j, "v"+(count++));
				}
			}
		}*/
		return expandPatterns;
	}
	
	private void conclude(ArrayList<ArrayList<String>> relatedTriples, String viConstant, ArrayList<ArrayList<String>> expandPatterns, ArrayList<String> stringPatterns){
		ArrayList<String> pattern = null;
		
		for(ArrayList<String> row : relatedTriples){
			pattern = new ArrayList<String>();
			if(RDF.type.getURI().contentEquals(row.get(1).substring(1))){
				continue;
				/*//add rdf:type triple
				if(row.get(0).contentEquals(viConstant)){
					pattern.add(vi);
					pattern.add(row.get(1));
					pattern.add(row.get(2));
				}*/
			}else{
				for(int i=0; i<row.size(); i++){
					if(row.get(i).contentEquals(viConstant)){
						pattern.add(vi);
					}else if(i==1){
						pattern.add(row.get(i));
					}else{
//						pattern.add("v");
						pattern.add(this.nvname);
					}
				}
			}
			
			/*for(int i=0; i<row.size(); i++){
				if(row.get(i).contentEquals(viConstant)){
					pattern.add(vi);
				}else if(i==1){
					if(RDF.type.getURI().contentEquals(row.get(i).substring(1))){// && !row.get(2).startsWith("v")){//remove v1 rdf:type v2
						break;
					}else{
						pattern.add(row.get(i));
					}
				}else{
//					pattern.add("v");
					pattern.add(this.nvname);
				}
			}*/
//			String[] r = row.subSequence(1, row.lastIndexOf("]")).toString().split(",");
//			for(int i=0; i<r.length; i++){
//				if(r[i].contentEquals(viConstant)){
//					pattern.add(vi);
//				}else if(i==1){
//					pattern.add(r[i]);
//				}else{
//					pattern.add("v");
//				}
//			}
			if(stringPatterns.contains(pattern.toString()) || pattern.size()<3){//remove v1 rdf:type v2
				continue;
			}else{
				expandPatterns.add(pattern);
				stringPatterns.add(pattern.toString());
			}
		}
	}
	
	private boolean removeTriples(ArrayList<String> resultRow, ArrayList<ArrayList<String>> relatedTriples){
		boolean removed = false;
		ArrayList<ArrayList<String>> fillingTriples = this.getFillingTriples(resultRow);
		ArrayList<Integer> idxToRemove = new ArrayList<Integer>();
		int tmpid = -1;
		for(ArrayList<String> row : fillingTriples){
			if((tmpid = this.tripleRows.indexOf(row.toString())) >= 0){
				idxToRemove.add(tmpid);
				removed = true;
			}else{
				removed = false;
				break;
			}
		}
		if(removed){
			String row = null; 
			Collections.sort(idxToRemove);
//			System.out.println("in Expand:"+idxToRemove.toString());
			int count=0;
			for(int idx : idxToRemove){
				row = this.tripleRows.get(idx-count);
				for(int i=0; i<relatedTriples.size(); ){
					if(relatedTriples.get(i).toString().contentEquals(row)){
						relatedTriples.remove(i);
					}else{
						i++;
					}
				}
				/*if(relatedTriples.contains(row)){
					relatedTriples.remove(relatedTriples.indexOf(row));
				}*/
				this.tripleRows.remove(idx-count);
				count++;
			}
		}
		return removed;
	}
	/*private boolean checkMatch(int pidx, int tidx, String viConstant){
		boolean match = false;
		ArrayList<String> pattern = (ArrayList<String>) Arrays.asList(this.patterns.get(pidx));
		ArrayList<String> triple = this.triples.get(tidx);
		String ep = null, et = null;
		if(pattern.size() == triple.size()){
			for(int i=0; i<pattern.size(); i++){
				ep = pattern.get(i);
				et = triple.get(i);
				if(ep.contentEquals(vi) && et.contentEquals(viConstant)){
					match = true;
				}else if(ep.startsWith("v")) {
					match = true;
				}else if(ep.contentEquals(et)){//e.g. prop,constant
					match = true;
				}else{
					match = false;
					break;
				}
			}
		}
		return match;
	}*/
	private ArrayList<ArrayList<String>> getFillingTriples(ArrayList<String> resultRow){
		ArrayList<String> variables = this.results.get(0);
		ArrayList<ArrayList<String>> rTriples = new ArrayList<ArrayList<String>>();
		String[] p;
		for(int i=0; i<this.patterns.size(); i++){
			p = this.patterns.get(i);
			ArrayList<String> et = new ArrayList<String>();
			for(int j=0; j<p.length; j++){
				if(p[j].startsWith("v")){
					et.add(resultRow.get(variables.indexOf(p[j])));//fill the triple with result
				}else{
					et.add(p[j]);//fill the triple with pattern element
				}
			}
			rTriples.add(et);
		}
		return rTriples;
	}
	private ArrayList<ArrayList<String>> getRelatedTriples(String viConstant){
		ArrayList<ArrayList<String>> relatedTriples = new ArrayList<ArrayList<String>>();//indexes of triples in this.triples whose vi=viConstant
		for(ArrayList<String> row : this.triples){
			int idx = row.indexOf(viConstant);
			if(idx==0 || idx==2){//viConstant appears on subject or object
				relatedTriples.add(row);
			}
		}
		return relatedTriples;
	}
	/*private ArrayList<String> getRelatedTriples(String viConstant){
		ArrayList<String> relatedTriples = new ArrayList<String>();//indexes of triples in this.triples whose vi=viConstant
		for(ArrayList<String> row : this.triples){
			int idx = row.indexOf(viConstant);
			if(idx==0 || idx==2){//viConstant appears on subject or object
				relatedTriples.add(row.toString());
			}
		}
		return relatedTriples;
	}*/
	/*private ArrayList<Integer> getRelatedPatterns(String vi){
		ArrayList<Integer> relatedPatterns = new ArrayList<Integer>();//indexes of patterns related to vi
		for(int i=0; i<this.patterns.size(); i++){
			ArrayList<String> row = (ArrayList<String>) Arrays.asList(this.patterns.get(i));
			if(row.contains(vi)){
				relatedPatterns.add(i);
			}
		}
		return relatedPatterns;
	}*/
	private ArrayList<ArrayList<String>> getTriples(ArrayList<Integer> doc_id){
		StringBuffer sqlpart = new StringBuffer();
		for(Integer id : doc_id){
			sqlpart.append(id+",");
		}
		if(sqlpart.length()>0){
			sqlpart.deleteCharAt(sqlpart.lastIndexOf(","));
		}
		try {
			Connection fconn = DBConnectionFactory.getConnection();//.getFalconConnection();
			PreparedStatement uri_pstmt = fconn.prepareStatement("select uri from uri where id=?");
			ResultSet uri_rs = null;
//			PreparedStatement pstmt = fconn.prepareStatement("select s,p,o from quadruple where c in ("+sqlpart.toString()+");");
			PreparedStatement pstmt = fconn.prepareStatement("select s,p,o from quadruple where doc_id in ("+sqlpart.toString()+");");
			ResultSet rs = pstmt.executeQuery();
			this.triples = new ArrayList<ArrayList<String>>();
			ArrayList<String> row = null;
			while(rs.next()){
				row = new ArrayList<String>();
				for(int i=1; i<=3; i++){
					if(rs.getString(i).startsWith("u")){//if uri
						uri_pstmt.setInt(1, Integer.valueOf(rs.getString(i).substring(1)));
						uri_rs = uri_pstmt.executeQuery();
						if(uri_rs.next()){
							row.add("u"+uri_rs.getString(1));
						}
					}else if(rs.getString(i).startsWith("b")){
						String nbstr = rs.getString(i);//e.g.  b322960:5
						int bndid = Integer.valueOf(nbstr.substring(1, nbstr.indexOf(":")));//get doc id of blanknode
						int bnid = Integer.valueOf(nbstr.substring(nbstr.indexOf(":")+1));
						uri_pstmt.setInt(1, bndid);
						uri_rs = uri_pstmt.executeQuery();
						if(uri_rs.next()){
							String bn = "_:IN<"+uri_rs.getString(1)+">NO"+bnid;
							row.add(bn);
						}
						
					}else{//if literal
						row.add(rs.getString(i));
					}
				}
				this.triples.add(row);
			}
			if(uri_rs!= null){
				uri_rs.close();
			}
			uri_pstmt.close();
			rs.close();
			pstmt.close();
			fconn.close();
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return this.triples;
	}
}
